package com.fsd.admin.service.impl;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fsd.admin.entity.activiti.ActivitiTask;
import com.fsd.admin.model.*;
import com.fsd.admin.service.*;
import com.fsd.core.activiti.ActivitiUtil;
import com.fsd.core.util.BeanToMapUtil;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import com.google.gson.Gson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fsd.core.service.impl.BaseServiceImpl;
import com.fsd.core.common.BusinessException;
import com.fsd.core.util.ParametersUtil;
import com.fsd.admin.dao.F_activitiDao;

@Service("f_activitiServiceImpl")
public class F_activitiServiceImpl extends BaseServiceImpl<F_activiti, String> implements F_activitiService{
    
    private static final Logger log = Logger.getLogger(F_activitiServiceImpl.class);
    private String depict = "";
    
    @Resource(name = "f_activitiDaoImpl")
	public void setBaseDao(F_activitiDao F_activitiDao) {
		super.setBaseDao(F_activitiDao);
	}
	
	@Resource(name = "f_activitiDaoImpl")
	private F_activitiDao objectDao;

	@Autowired
    private Z_projectService projectService;

    @Autowired
	private RepositoryService repositoryService;

	@Autowired
	private TaskService taskService;

	@Autowired
	private RuntimeService runtimeService;

	@Autowired
	private HistoryService historyService;

	@Autowired
	private Z_projectauditService projectauditService;

	@Autowired
	private A_EmployeeService employeeService;

	@Autowired
	private F_formService formService;

    /**
	 * 加载流程设计分页数据
	 * @param param
	 * @return
	 * @throws Exception
	 */
    @Override
	public ParametersUtil getDesignPageList(ParametersUtil param, A_Employee employee) throws Exception{
		List<Model> models = repositoryService.createModelQuery().list();
		List<Model> newModels = new ArrayList<Model>();
		if(param.getJsonData() != null && !"".equals(param.getJsonData())){
			Gson gs = new Gson();
			Map objectMap = gs.fromJson(param.getJsonData(), Map.class);
			if(objectMap.get("name") != null && !"".equals(objectMap.get("name"))){
				for (Model model : models) {
					if(model.getName().indexOf(objectMap.get("name").toString()) != -1){
						newModels.add(model);
					}
				}
			}else{
				newModels = models;
			}
		}else{
			newModels = models;
		}
		param.setData(newModels);
		return param;
	}

	/**
	 * 加载流程定义列表
	 * @param param
	 * @param employee
	 * @return
	 * @throws Exception
	 */
	@Override
	public ParametersUtil getProcessDefinitionPageList(ParametersUtil param, A_Employee employee) throws Exception{
		List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();
		List<Map<String, Object>> resultList = new ArrayList<>();
		for (ProcessDefinition processDefinition : list) {
			Map<String, Object> map = new HashMap<>();
			map.put("id", processDefinition.getId());
			map.put("key", processDefinition.getKey());
			map.put("deploymentid", processDefinition.getDeploymentId());
			map.put("name", processDefinition.getName());
			map.put("resourcename", processDefinition.getResourceName());
			map.put("diagramresourcename", processDefinition.getDiagramResourceName());
			resultList.add(map);
		}
		param.setData(resultList);
		return param;

//		List<HistoricActivityInstance>  list= historyService // 历史相关Service
//				.createHistoricActivityInstanceQuery().finished() // 创建历史活动实例查询
//				.list();
//		//List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().list();
//		for(HistoricActivityInstance hai:list){
//			System.out.println("活动ID:"+hai.getId());
//			System.out.println("流程实例ID:"+hai.getProcessInstanceId());
//			System.out.println("活动名称："+hai.getActivityName());
//			System.out.println("办理人："+hai.getAssignee());
//			System.out.println("开始时间："+hai.getStartTime());
//			System.out.println("结束时间："+hai.getEndTime());
//			System.out.println("=================================");
//			ActivitiUtil.deleteHistoricProcessInstanceById(hai.getProcessInstanceId());
//		}
	}

	/**
	 * 加载流程实例列表
	 * @param param
	 * @param employee
	 * @return
	 * @throws Exception
	 */
	@Override
	public ParametersUtil getProcessInstancePageList(ParametersUtil param, A_Employee employee) throws Exception{
		// 指定流程定义key，只查询某个业务流程的实例
		String processDefinitionKey = "";

		if(param.getJsonData() != null && !"".equals(param.getJsonData())){
			Gson gs = new Gson();
			Map objectMap = gs.fromJson(param.getJsonData(), Map.class);
			if(objectMap.get("key") != null && !"".equals(objectMap.get("key"))){
				processDefinitionKey = objectMap.get("key").toString();
			}
		}
		if("".equals(processDefinitionKey)){
			throw new BusinessException("缺少流程定义KEY参数");
		}

		// 创建历史流程实例，查询对象
		HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery();
		// 设置查询条件
		historicProcessInstanceQuery.processDefinitionKey(processDefinitionKey);

		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");

		//数据列表
		List<HistoricProcessInstance> list = historicProcessInstanceQuery.list();

		List<Map<String, Object>> resultList = new ArrayList<>();
		for (HistoricProcessInstance historicProcessInstance : list) {
			Map<String, Object> map = new HashMap<>();
			// 流程实例id
			map.put("id", historicProcessInstance.getId());
			// 业务标识
			map.put("businessKey", historicProcessInstance.getBusinessKey());
			// 流程实例所属流程定义id
			map.put("processDefinitionId", historicProcessInstance.getProcessDefinitionId());
			// 开始执行时间
			map.put("startTime", dateFormat.format(historicProcessInstance.getStartTime()));
			//结束执行时间
			if(historicProcessInstance.getEndTime() != null){
				map.put("endTime", dateFormat.format(historicProcessInstance.getEndTime()));
			}else{
				map.put("endTime", "未知");
			}
			//执行时长
			if(historicProcessInstance.getDurationInMillis() != null){
				Long durationInMillis = historicProcessInstance.getDurationInMillis();
				StringBuffer duration = new StringBuffer();
				long day = durationInMillis/(24*60*60);
				if(day != 0){
					duration.append(day + "天");
				}
				long hour = durationInMillis%(24*60*60)/(60*60);
				if(hour != 0){
					duration.append(hour + "小时");
				}
				long minute = durationInMillis%(24*60*60)%(60*60)/60;
				if(minute != 0){
					duration.append(minute + "分钟");
				}
				long second = durationInMillis%(24*60*60)%(60*60)%60;
				if(second != 0){
					duration.append(second + "秒");
				}
				map.put("durationInMillis", duration.toString());
			}else{
				map.put("durationInMillis", "未知");
			}
			// 流程是否结束
			ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(historicProcessInstance.getId()).singleResult();
			if(pi != null){
				map.put("state", "执行中");
				map.put("activiti", pi.getActivityId());
			}else{
				map.put("state", "已结束");
				map.put("activiti", "无");
			}
			resultList.add(map);
		}
		param.setData(resultList);
		return param;
	}

    /**
     * 加载用户任务列表
     * @param param
     * @param employee
     * @return
     * @throws Exception
     */
    @Override
    public ParametersUtil getTaskPageList(ParametersUtil param, A_Employee employee) throws Exception{
		List<Task> list = ActivitiUtil.getTaskList(employee.getId());
		List<ActivitiTask> taskList = new ArrayList<>();
		if (list != null && list.size() > 0) {
			for (Task task : list) {
				ActivitiTask activitiTask = new ActivitiTask();
				// 任务ID
				activitiTask.setId(task.getId());
				// 任务名称
				activitiTask.setName(task.getName());
				// 任务执行人编号
				activitiTask.setAssignee(task.getAssignee());
				// 流程实例ID
				activitiTask.setProcessInstanceId(task.getProcessInstanceId());
				// 任务执行人姓名
				activitiTask.setColumn1(employee.getRealname());

				// 流程创建日期
				SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
				activitiTask.setCreateTime(format.format(task.getCreateTime()));

				//流程实例ID
				String processInstanceId = task.getProcessInstanceId();
				//使用流程实例ID，查询正在执行的执行对象表，获取当前活动对应的流程实例对象
				ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
				//当前流程名称
				activitiTask.setColumn2(pi.getProcessDefinitionName());
				activitiTask.setColumn6(pi.getBusinessKey());
				//任务申请人
				String userid = Authentication.getAuthenticatedUserId();
				if(userid == null || "".equals(userid)){
					HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
					if(historicProcessInstance != null) {
						userid = historicProcessInstance.getStartUserId();
					}
				}
				activitiTask.setColumn3(userid);
				activitiTask.setColumn4(employeeService.get(userid).getRealname());

				//当前任务对应的表单
				String formKey = task.getFormKey();
				if(formKey != null && !"".equals(formKey)){
					F_form form = formService.get(formKey);
					if(form == null){
						throw new BusinessException("任务对应的表单不存在");
					}
					activitiTask.setColumn5(form.getF_wordtemplate());
					activitiTask.setFormMap(BeanToMapUtil.convertBean(form));
				}

				//当前任务的下一步操作信息
				String type = ActivitiUtil.getNextTaskType(task.getId());
				if(org.apache.commons.lang3.StringUtils.isNotEmpty(type)){
					if(type.equals(ActivitiUtil.TASK_TYPE_USERTASK)){
						//如果下个节点是用户任务
						//TaskDefinition nextTask = ActivitiUtil.getNextTaskInfo(task.getId(), "");

					}else if(type.equals(ActivitiUtil.TASK_TYPE_EXCLUSIVEGATEWAY)){
						//如果下个节点是排他网关
						List<PvmTransition> nextList = ActivitiUtil.getNexGatewayInfo(task.getId());
						List<Map<String, Object>> nexGatewayList = new ArrayList();
						for (PvmTransition pvmTransition : nextList) {
							String name = pvmTransition.getProperty("name").toString();
							String conditionText = pvmTransition.getProperty("conditionText").toString();
							String state = conditionText.substring(conditionText.length() -2, conditionText.length()-1);
							Map<String, Object> map = new HashMap<>();
							map.put("name", name);
							map.put("state", state);
							nexGatewayList.add(map);
						}
						activitiTask.setNextNodeList(nexGatewayList);
					}
				}

				//当前任务的历史表单数据信息
				List<HistoricTaskInstance> finishedTaskList = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).finished().list();
				List<Map<String, Object>> finishedFormList = new ArrayList();
				for(HistoricTaskInstance historicTaskInstance : finishedTaskList){
					String finishedFormKey = historicTaskInstance.getFormKey();
					if(finishedFormKey != null && !"".equals(finishedFormKey)){
						F_form form = formService.get(finishedFormKey);
						finishedFormList.add(BeanToMapUtil.convertBean(form));
					}
				}
				activitiTask.setFinishedFormList(finishedFormList);
				taskList.add(activitiTask);
			}
		}
		param.setData(taskList);
		return param;
    }

	/**
	 * 任务处理
	 * @param taskId
	 * @param state
	 * @throws Exception
	 */
	@Override
	public void disposeTask(String taskId, String state, String message) throws Exception{
		Map<String, Object> variables = new HashMap<>();
		if(state != null && !"".equals(state)){
			variables.put("state", Integer.valueOf(state));
		}
		// 根据任务ID获得任务信息
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		// 给任务添加批注
		taskService.addComment(taskId, task.getProcessInstanceId(), message);
		// 提交任务
		taskService.complete(taskId, variables);
	}

	/**
	 * 选择任务处理
	 * @param taskId
	 * @param ids
	 * @throws Exception
	 */
	@Override
	public void disposeChooseTask(String taskId, String ids) throws Exception{
		Map<String, Object> variables = new HashMap<>();
		List<String> assigneeList = new ArrayList<String>();
		String[] dir = ids.split(",");
		for (String id : dir) {
			assigneeList.add(id);
		}
		variables.put("publicityList",assigneeList);
		taskService.complete(taskId, variables);
	}

    /**
	 * 编辑流程
	 * @param activiti
	 * @param employee
	 * @throws Exception
	 */
    @Override
	public void save(F_activiti activiti, A_Employee employee) throws Exception{
        if(activiti.getId() != null && !"".equals(activiti.getId())){
            //修改
            F_activiti old_obj = objectDao.get(activiti.getId());
            
            objectDao.update(old_obj);
        }else{
            //添加
			// 元数据信息
			Model newModel = repositoryService.newModel();
			ObjectMapper objectMapper = new ObjectMapper();
			ObjectNode modelObjectNode = objectMapper.createObjectNode();
			modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, activiti.getF_name());
			modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
			modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, StringUtils.defaultString(activiti.getF_description()));
			newModel.setMetaInfo(modelObjectNode.toString());
			newModel.setName(activiti.getF_name());
			newModel.setKey(StringUtils.defaultString(StringUtils.defaultString(activiti.getF_key())));
			repositoryService.saveModel(newModel);
			// 创建所必须的JSON数据
			ObjectNode editorNode = objectMapper.createObjectNode();
			editorNode.put("id", "canvas");
			editorNode.put("resourceId", "canvas");
			ObjectNode stencilSetNode = objectMapper.createObjectNode();
			stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
			editorNode.put("stencilset", stencilSetNode);
			repositoryService.addModelEditorSource(newModel.getId(), editorNode.toString().getBytes("utf-8"));
        }
    }

	/**
	 * 部署流程
	 * @param parameters
	 * @throws Exception
	 */
	@Override
	public void deployObject(ParametersUtil parameters, A_Employee employee) throws Exception{
		Gson gs = new Gson();
		Map objectMap = gs.fromJson(parameters.getJsonData(), Map.class);
		ArrayList<String> dir = (ArrayList<String>) objectMap.get("ids");
		for (String id : dir) {
			Model modelData = repositoryService.getModel(id);
			byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());
			if (bytes == null) {
				throw new BusinessException("模型数据为空，请先设计流程并成功保存，再进行发布。");
			}
			JsonNode modelNode = new ObjectMapper().readTree(bytes);
			BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
			if(model.getProcesses().size()==0){
				throw new BusinessException("数据模型不符要求，请至少设计一条主线流程。");
			}
			byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(model);
			//发布流程
			String processName = modelData.getName() + ".bpmn20.xml";
			Deployment deployment = repositoryService.createDeployment().name(modelData.getName()).addString(processName, new String(bpmnBytes, "UTF-8")).deploy();
			modelData.setDeploymentId(deployment.getId());
			repositoryService.saveModel(modelData);
		}
	}
    
    /**
	 * 删除模型
	 * @param parameters
	 * @throws Exception
	 */
    @Override
	public void deleteModel(ParametersUtil parameters, A_Employee employee) throws Exception{
		Gson gs = new Gson();
		Map objectMap = gs.fromJson(parameters.getJsonData(), Map.class);
		ArrayList<String> dir = (ArrayList<String>) objectMap.get("ids");
		for (String id : dir) {
			repositoryService.deleteModel(id);
		}
	}

	/**
	 * 删除已部署的模型
	 * @param parameters
	 * @param employee
	 * @throws Exception
	 */
	@Override
	public void deleteDeployment(ParametersUtil parameters, A_Employee employee) throws Exception{
		Gson gs = new Gson();
		Map objectMap = gs.fromJson(parameters.getJsonData(), Map.class);
		ArrayList<String> dir = (ArrayList<String>) objectMap.get("ids");
		for (String id : dir) {
			repositoryService.deleteDeployment(id, true);
		}
	}

    /**
	 * 根据ID加载对象
	 * @param parameters
	 * @return
	 * @throws Exception
	 */
	public F_activiti getObjectById(ParametersUtil parameters) throws Exception{
		Gson gs = new Gson();
		Map objectMap = gs.fromJson(parameters.getJsonData(), Map.class);
		if(objectMap.get("id") == null && "".equals(objectMap.get("id"))){
			throw new BusinessException(depict + "获取缺少ID参数!");
		}
		F_activiti obj = objectDao.get(objectMap.get("id").toString());
		if(obj == null){
			throw new BusinessException(depict + "数据不存在!");
		}
		
		return obj;
	}

	/**
	 * 根据任务ID加载流程历史审核信息
	 * @param parameters
	 * @return
	 * @throws Exception
	 */
	public List<Map<String, Object>> getHistoryListByTaskId(ParametersUtil parameters) throws Exception{
		Gson gs = new Gson();
		Map objectMap = gs.fromJson(parameters.getJsonData(), Map.class);
		if(objectMap.get("taskId") == null && "".equals(objectMap.get("taskId"))){
			throw new BusinessException(depict + "获取缺少任务ID参数!");
		}
		String taskId = objectMap.get("taskId").toString();
		// 根据任务ID获得任务信息
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery().processInstanceId(task.getProcessInstanceId()).list();
		List<Map<String, Object>> resultList = new ArrayList<>();
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		for (HistoricTaskInstance historicTaskInstance : list) {
			Map<String, Object> map = new HashMap<>();
			map.put("id", historicTaskInstance.getId());
			map.put("name", historicTaskInstance.getName());
			// 开始执行时间
			map.put("startTime", dateFormat.format(historicTaskInstance.getStartTime()));
			//结束执行时间
			if(historicTaskInstance.getEndTime() != null){
				map.put("endTime", dateFormat.format(historicTaskInstance.getEndTime()));
			}else{
				map.put("endTime", "未知");
			}
			//执行时长
			if(historicTaskInstance.getDurationInMillis() != null){
				Long durationInMillis = historicTaskInstance.getDurationInMillis();
				StringBuffer duration = new StringBuffer();
				long day = durationInMillis/(24*60*60);
				if(day != 0){
					duration.append(day + "天");
				}
				long hour = durationInMillis%(24*60*60)/(60*60);
				if(hour != 0){
					duration.append(hour + "小时");
				}
				long minute = durationInMillis%(24*60*60)%(60*60)/60;
				if(minute != 0){
					duration.append(minute + "分钟");
				}
				long second = durationInMillis%(24*60*60)%(60*60)%60;
				if(second != 0){
					duration.append(second + "秒");
				}
				map.put("durationInMillis", duration.toString());
			}else{
				map.put("durationInMillis", "未知");
			}
			if(historicTaskInstance.getDurationInMillis() == null){
				map.put("state", "执行中");
			}else{
				map.put("state", "已结束");
			}
			List<Comment> commentsList = taskService.getTaskComments(historicTaskInstance.getId());
			if(commentsList != null && commentsList.size() > 0){
				map.put("message", commentsList.get(0).getFullMessage());
			}else{
				map.put("message", "无");
			}
			resultList.add(map);
		}
		return resultList;
	}
}
